﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Motion
{
    /// <summary>
    /// 消息头格式
    /// </summary>
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct MessageHeader
    {
        public int UserId;                  //发送方的用户名字
        public long MessageID;              //发送方消息ID
        public long AnswerMsgID;            //标记为某一个ID的回复信息
        public int Checksum;                //校验和
        public bool bReaded;                //消息是否已读
        public CommandType CmdType;         //消息类型
        public ResponseType ReTurnType;     //执行返回的结果
        public DateTime Timestamp;          //时间戳
        public long Para_1;                 //预留参数
        public long Para_2;                 //预留参数
        public long Para_3;                 //预留参数
        public long Para_4;                 //预留参数
        public long Para_5;                 //预留参数
        public double Para_6;               //预留参数
        public double Para_7;               //预留参数
        public double Para_8;               //预留参数
        public double Para_9;               //预留参数
        public double Para_10;              //预留参数

        public MessageHeader(int userId, long messageId, long answerMsgid, int checksum, CommandType type, ResponseType reTurnType)
        {
            UserId = userId;
            MessageID = messageId;
            AnswerMsgID = answerMsgid;
            Checksum = checksum;
            CmdType = type;
            ReTurnType = reTurnType;
            Timestamp = DateTime.Now;
            Para_1 = 0;
            Para_2 = 0;
            Para_3 = 0;
            Para_4 = 0;
            Para_5 = 0;
            bReaded = false;
            Para_6 = 0;
            Para_7 = 0;
            Para_8 = 0;
            Para_9 = 0;
            Para_10 = 0;
        }
        public MessageHeader(CommandType type)
        {
            long.TryParse(DateTime.Now.ToString("yyyyMMddHHmmssfff"), out long msgID);
            UserId = 0;
            MessageID = msgID;
            AnswerMsgID = 0;
            Checksum = 0;
            CmdType = type;
            ReTurnType = ResponseType.None;
            Timestamp = DateTime.Now;
            Para_1 = 0;
            Para_2 = 0;
            Para_3 = 0;
            Para_4 = 0;
            Para_5 = 0;
            Para_6 = 0;
            Para_7 = 0;
            Para_8 = 0;
            Para_9 = 0;
            Para_10 = 0;
            bReaded = false;
        }
        public MessageHeader(ResponseType reTurnType)
        {
            long.TryParse(DateTime.Now.ToString("yyyyMMddHHmmssfff"), out long msgID);
            UserId = 0;
            MessageID = msgID;
            AnswerMsgID = 0;
            Checksum = 0;
            CmdType = CommandType.None;
            ReTurnType = reTurnType;
            Timestamp = DateTime.Now;
            Para_1 = 0;
            Para_2 = 0;
            Para_3 = 0;
            Para_4 = 0;
            Para_5 = 0;
            Para_6 = 0;
            Para_7 = 0;
            Para_8 = 0;
            Para_9 = 0;
            Para_10 = 0;
            bReaded = false;
        }
    }
    public enum CommandType
    {
        None = 0,
        //初始化
        Init,
        //拍照初始化
        GrabInit,
        //单张图片
        SingleGrab,
        //单次循环拍照
        SinglePanelGrab,
        //自动运行
        Running,
        //退出运行
        StopRunning,
        //复位
        Reset,
        //调宽调宽
        Move_T_abs,
        //增量调宽
        Move_T_add,
        //设置NG信号的输出模式
        NGSignalOutputType,
        //输出NG信号。
        PidNGSignal,
        //心跳
        Heartbeat,
        //循环静止拍照
        PanelRestRunningLoop,
        //循环检测
        RunningLoop,

        //运行状态下采集
        RunningToGrab,

        //移动
        MoveAxis,
    }

    public enum ResponseType
    {
        //执行结果
        None = 0,
        OK,
        ERROR,
        GRAB_ERROR,
        GRAB_FINSH,

        NEW_IMAGE,
        NEW_PANEL,
    }
    /// <summary>
    /// 图片帧格式：
    /// ImageData
    /// 图片字节流 = Length * Width * channel
    /// </summary>
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct ImageData
    {
        public int Length;                  // 单张图片长宽
        public int Width;                   //单张图片的宽
        public int Channel;                 //通道数
        public int Index;                   //图片编号
        public int DlpLocationIndex;        //光机的位置坐标
        public int DlpImageIndex;           //光机的图片坐标
        public long Uuid;                   //PID
        public int BarCodeLength;           //条码长度
        public int ImageBufferLength;       //图片长度
        public bool bReaded;                //消息是否已读
        public long Para_1;                 //预留参数
        public long Para_2;                 //预留参数
        public long Para_3;                 //预留参数
        public long Para_4;                 //预留参数
        public long Para_5;                 //预留参数
        public double Para_6;               //预留参数
        public double Para_7;               //预留参数
        public double Para_8;               //预留参数
        public double Para_9;               //预留参数
        public double Para_10;              //预留参数
    }

    public enum UserType
    {
        //客户端，初始化成功后，写入的初始化信息。
        CommunicationInitMsg = 0,
        //运动控制作为服务端，回复客户端的信息。
        Server,
        //服务端回复的心跳区
        ServerHeart,
        //AOI、SPI作为消费端,客户端发送的命令区
        Client,
        //客户段发送的心跳区
        ClientHeart,
    }

    public enum UserID
    {
        ServerMotion = 0,
        Client_A = 1,
        Client_B = 2,
        Client_C = 3,
        Client_D = 4,
    }
    public class CommunicationHelper
    {
        #region 单列模式
        private static CommunicationHelper _Instance = new CommunicationHelper();
        public static CommunicationHelper Instance
        {
            get
            {
                return _Instance;
            }
        }
        #endregion
        const string keyString = "defghijk1234mnopq#$%^&*()_+-=[rstuv567lwxyz089!@]{}|;:";
        const string memoryMappedFileName = "Global\\" + keyString;
        const string eventName = "Global\\SharedDataReadyEvent";
        static Mutex[] mutexArray;

        /// <summary>
        /// 帧的格式：MessageHeader + MessageHeader + ImageData + Barcode + Image+ ImageData + Barcode + Image+ ImageData + Barcode + Image+ ImageData + Barcode + Image
        /// </summary>
        static int MessageHeaderLength = Marshal.SizeOf(typeof(MessageHeader));
        /// <summary>
        /// 信息头数量
        /// </summary>
        static int MessageHeaderCount = 5;
        /// <summary>
        /// ImageData的长度
        /// </summary>
        static int ImageDataLength = Marshal.SizeOf(typeof(ImageData));
        /// <summary>
        /// 图片数据的长度
        /// </summary>
        static int ImageBufferLength;
        /// <summary>
        /// 图片帧的数量
        /// </summary>
        static int ImageBufferCount;
        /// <summary>
        /// 条码长度
        /// </summary>
        static int BarcodeLength;
        private MemoryMappedFile mmf_MotionHelper;
        private MemoryMappedViewAccessor[] accessor_MotionHelper;

        public int Init(int imageBufferlength, int imageBufferCount, int barcodeLength = 256, bool IsWriter = true)
        {
            try
            {
                ImageBufferLength = imageBufferlength;
                ImageBufferCount = imageBufferCount;
                BarcodeLength = barcodeLength;

                int iCount = MessageHeaderCount + ImageBufferCount;
                //初始化Mutex
                mutexArray = new Mutex[iCount];
                for (int i = 0; i < iCount; i++)
                {
                    string MutexString = "Global\\" + keyString + i;
                    mutexArray[i] = new Mutex(false, MutexString);
                }
                //初始化MemoryMappedViewAccessor
                accessor_MotionHelper = new MemoryMappedViewAccessor[iCount];
                //初始化MemoryMappedFile
                Int64 MemSize = MessageHeaderLength * MessageHeaderCount + (ImageDataLength + BarcodeLength + ImageBufferLength) * ImageBufferCount;
                if (IsWriter) mmf_MotionHelper = MemoryMappedFile.CreateOrOpen(memoryMappedFileName, MemSize);
                else
                {
                    mmf_MotionHelper = MemoryMappedFile.OpenExisting(memoryMappedFileName);
                    //读取信息头
                    accessor_MotionHelper[0] = mmf_MotionHelper.CreateViewAccessor(0, MessageHeaderLength);
                    MessageHeader InitMsg = new MessageHeader();
                    ReadOneMsg(0, ref InitMsg);
                    if (InitMsg.Para_1 != BarcodeLength) return -2;
                    if (InitMsg.Para_2 != imageBufferlength) return -3;
                    if (InitMsg.Para_3 != ImageBufferCount) return -4;
                    if (InitMsg.Para_4 != MessageHeaderCount) return -5;
                    if (InitMsg.Para_5 != MessageHeaderLength) return -6;
                    if (InitMsg.Para_6 != ImageDataLength) return -7;
                    accessor_MotionHelper[0].Dispose();
                }
                //初始化MemoryMappedViewAccessor
                accessor_MotionHelper = new MemoryMappedViewAccessor[iCount];
                for (int i = 0; i < MessageHeaderCount; i++)
                {
                    accessor_MotionHelper[i] = mmf_MotionHelper.CreateViewAccessor(MessageHeaderLength * i, MessageHeaderLength);
                }
                for (int i = MessageHeaderCount; i < iCount; i++)
                {
                    accessor_MotionHelper[i] = mmf_MotionHelper.CreateViewAccessor(MessageHeaderLength * MessageHeaderCount + (ImageDataLength + BarcodeLength + ImageBufferLength) * (i - MessageHeaderCount), ImageDataLength + ImageBufferLength + BarcodeLength);
                }
                if (IsWriter)
                {
                    ResetBuffer();
                    MessageHeader header = new MessageHeader();
                    header.CmdType = CommandType.None;
                    header.ReTurnType = ResponseType.None;
                    //重置服务端的信息区
                    WriteOneMsg((int)UserType.Server, header);
                    WriteOneMsg((int)UserType.ServerHeart, header);

                    //写入初始化区。
                    MessageHeader headerHeart = new MessageHeader();
                    long.TryParse(DateTime.Now.ToString("yyyyMMddHHmmssfff"), out long msgID);
                    headerHeart.UserId = (int)UserID.ServerMotion;
                    headerHeart.Timestamp = DateTime.Now;
                    headerHeart.MessageID = msgID;
                    headerHeart.Para_1 = barcodeLength;
                    headerHeart.Para_2 = imageBufferlength;
                    headerHeart.Para_3 = ImageBufferCount;
                    headerHeart.Para_4 = MessageHeaderCount;
                    headerHeart.Para_5 = MessageHeaderLength;
                    headerHeart.Para_6 = ImageDataLength;
                    //将来初始化的信息，写入该区域。供客户端使用。
                    WriteOneMsg((int)UserType.CommunicationInitMsg, headerHeart);
                }
                else
                {
                    MessageHeader header = new MessageHeader();
                    header.CmdType = CommandType.None;
                    header.ReTurnType = ResponseType.None;
                    //重置服务端的信息区
                    WriteOneMsg((int)UserType.Client, header);
                    WriteOneMsg((int)UserType.ClientHeart, header);
                }
                return 1;
            }
            catch (Exception)
            {
                return -1;
                throw;
            }
            finally
            {

            }
        }
        public void ResetBuffer()
        {
            //初始化全部的imagedata
            for (int i = 0; i < ImageBufferCount; i++)
            {
                ImageData imageData = new ImageData();
                imageData.bReaded = true;
                WriterOneImageData(i, imageData);
            }
        }
        public void Dispose()
        {
            mmf_MotionHelper?.Dispose();
            foreach (var item in accessor_MotionHelper)
            {
                item?.Dispose();
            }
        }
        public void WriteOneMsg(int iLocation, MessageHeader message)
        {
            mutexArray[iLocation].WaitOne();
            accessor_MotionHelper[iLocation].Write(0, ref message);
            mutexArray[iLocation].ReleaseMutex();
        }
        public void ReadOneMsg(int iLocation, ref MessageHeader message)
        {
            mutexArray[iLocation].WaitOne();
            accessor_MotionHelper[iLocation].Read(0, out message);
            //如果未读，则标记为已读
            if (!message.bReaded)
            {
                message.bReaded = true;
                accessor_MotionHelper[iLocation].Write(0, ref message);
                message.bReaded = false;
            }
            mutexArray[iLocation].ReleaseMutex();
        }
        public void WriterOneImageData(int iLocation, ImageData imageData)
        {
            mutexArray[iLocation + MessageHeaderCount].WaitOne();
            accessor_MotionHelper[iLocation + MessageHeaderCount].Write(0, ref imageData);
            mutexArray[iLocation + MessageHeaderCount].ReleaseMutex();
        }
        public void WriterOneImageDataAndBuffer(int iLocation, ImageData imageData, ref byte[] barcodeBuffer, ref byte[] imgBuffer)
        {
            mutexArray[iLocation + MessageHeaderCount].WaitOne();
            unsafe
            {
                byte* ptr = null;
                accessor_MotionHelper[iLocation + MessageHeaderCount].SafeMemoryMappedViewHandle.AcquirePointer(ref ptr);  // 不需要 unsafe
                Marshal.Copy(imgBuffer, 0, IntPtr.Add((IntPtr)ptr, ImageDataLength + BarcodeLength), imageData.ImageBufferLength);
            }
            accessor_MotionHelper[iLocation + MessageHeaderCount].Write(0, ref imageData);
            accessor_MotionHelper[iLocation + MessageHeaderCount].WriteArray(ImageDataLength, barcodeBuffer, 0, imageData.BarCodeLength);
            //accessor_MotionHelper[iLocation + MessageHeaderCount].WriteArray(ImageDataLength + BarcodeLength, imgBuffer, 0, imageData.ImageBufferLength);
            mutexArray[iLocation + MessageHeaderCount].ReleaseMutex();
        }
        public void ReadOneImageData(int iLocation, ref ImageData imageData)
        {
            mutexArray[iLocation + MessageHeaderCount].WaitOne();
            accessor_MotionHelper[iLocation + MessageHeaderCount].Read(0, out imageData);
            mutexArray[iLocation + MessageHeaderCount].ReleaseMutex();
        }
        public void ReadOneImageDataBuffer(int iLocation, ImageData imageData, ref byte[] barcodeBuffer, ref byte[] imgBuffer)
        {
            mutexArray[iLocation + MessageHeaderCount].WaitOne();
            accessor_MotionHelper[iLocation + MessageHeaderCount].ReadArray(ImageDataLength, barcodeBuffer, 0, imageData.BarCodeLength);

            unsafe
            {
                // 获取共享内存的指针
                byte* ptr = null;
                accessor_MotionHelper[iLocation + MessageHeaderCount].SafeMemoryMappedViewHandle.AcquirePointer(ref ptr);  // 不需要 unsafe
                // 将共享内存中的数据复制到托管内存
                Marshal.Copy(IntPtr.Add((IntPtr)ptr, ImageDataLength + BarcodeLength), imgBuffer, 0, imageData.ImageBufferLength);
            }
            //accessor_MotionHelper[iLocation + MessageHeaderCount].ReadArray(ImageDataLength + BarcodeLength, imgBuffer, 0, imageData.ImageBufferLength);
            mutexArray[iLocation + MessageHeaderCount].ReleaseMutex();
        }
    }

    public class CommunicationServerHelper
    {
        #region 单列模式
        private static CommunicationServerHelper _Instance = new CommunicationServerHelper();
        public static CommunicationServerHelper Instance
        {
            get
            {
                return _Instance;
            }
        }
        #endregion
        /// <summary>
        /// 初始化，图片的长宽通道数
        /// </summary>
        /// <param name="iWidth"></param>
        /// <param name="iHeight"></param>
        /// <param name="iChannel"></param>
        /// <returns></returns>
        public int Init(int iWidth, int iHeight, int iChannel)
        {
            return CommunicationHelper.Instance.Init(iWidth * iHeight * iChannel, 100);
        }
        public int ResetBuffer()
        {
            try
            {
                CommunicationHelper.Instance.ResetBuffer();
                return 1;
            }
            catch (Exception)
            {
                return -1;
                throw;
            }
        }
        /// <summary>
        /// 回复一条信息
        /// </summary>
        /// <param name="ReceivedMsg"></param>
        /// <param name="SendMsg"></param>
        public void RespondOneMsg(ref MessageHeader ReceivedMsg,ref MessageHeader SendMsg)
        {
            long.TryParse(DateTime.Now.ToString("yyyyMMddHHmmssfff"), out long msgID);
            SendMsg.AnswerMsgID = ReceivedMsg.MessageID;
            SendMsg.UserId = (int)UserID.ServerMotion;
            SendMsg.Timestamp = DateTime.Now;
            SendMsg.MessageID = msgID;
            CommunicationHelper.Instance.WriteOneMsg((int)UserType.Server, SendMsg);
        }
        /// <summary>
        /// 发送一条信息
        /// </summary>
        /// <param name="SendMsg"></param>
        public void SendOneMsg(ref MessageHeader SendMsg)
        {
            long.TryParse(DateTime.Now.ToString("yyyyMMddHHmmssfff"), out long msgID);
            SendMsg.UserId = (int)UserID.ServerMotion;
            SendMsg.Timestamp = DateTime.Now;
            SendMsg.MessageID = msgID;
            CommunicationHelper.Instance.WriteOneMsg((int)UserType.Server, SendMsg);
        }
        /// <summary>
        /// 收取一条信息
        /// </summary>
        /// <param name="ReceiveMsg"></param>
        public void ReceiveOneMsg(ref MessageHeader ReceiveMsg)
        {
            CommunicationHelper.Instance.ReadOneMsg((int)UserType.Client, ref ReceiveMsg);
        }
        /// <summary>
        /// 发送一张图片头+条码Buffer+图片Buffer
        /// </summary>
        /// <param name="iID"></param>
        /// <param name="imageData"></param>
        /// <param name="byteArray"></param>
        /// <param name="imageBytes"></param>
        public void SendOneImageDataAndBuffer(int iID, ImageData imageData, ref byte[] byteArray, ref byte[] imageBytes)
        {
            CommunicationHelper.Instance.WriterOneImageDataAndBuffer(iID, imageData, ref byteArray, ref imageBytes);
        }
        public void ReceiveOneHeartMsg(ref MessageHeader ReceiveMsg)
        {
            CommunicationHelper.Instance.ReadOneMsg((int)UserType.ClientHeart, ref ReceiveMsg);
        }
        public void RespondOneHeartMsg(ref MessageHeader ReceivedMsg, ref MessageHeader SendMsg)
        {
            long.TryParse(DateTime.Now.ToString("yyyyMMddHHmmssfff"), out long msgID);
            SendMsg.AnswerMsgID = ReceivedMsg.MessageID;
            SendMsg.UserId = (int)UserID.ServerMotion;
            SendMsg.Timestamp = DateTime.Now;
            SendMsg.MessageID = msgID;
            CommunicationHelper.Instance.WriteOneMsg((int)UserType.ServerHeart, SendMsg);
        }
    }
    public class CommunicationClientHelper
    {
        #region 单列模式
        private static CommunicationClientHelper _Instance = new CommunicationClientHelper();
        public static CommunicationClientHelper Instance
        {
            get
            {
                return _Instance;
            }
        }
        #endregion
        /// <summary>
        /// 初始化，图片的长宽通道数
        /// </summary>
        /// <param name="iWidth"></param>
        /// <param name="iHeight"></param>
        /// <param name="iChannel"></param>
        /// <returns></returns>
        public int Init(int iWidth,int iHeight,int iChannel)
        {
            return CommunicationHelper.Instance.Init(iWidth * iHeight * iChannel, 100, 256, false);
        }
        /// <summary>
        /// 回复一条信息
        /// </summary>
        /// <param name="ReceivedMsg"></param>
        /// <param name="SendMsg"></param>
        public void RespondOneMsg(ref MessageHeader ReceivedMsg, ref MessageHeader SendMsg)
        {
            long.TryParse(DateTime.Now.ToString("yyyyMMddHHmmssfff"), out long msgID);
            SendMsg.AnswerMsgID = ReceivedMsg.MessageID;
            SendMsg.UserId = (int)UserID.Client_A;
            SendMsg.Timestamp = DateTime.Now;
            SendMsg.MessageID = msgID;
            CommunicationHelper.Instance.WriteOneMsg((int)UserType.Client, SendMsg);
        }
        /// <summary>
        /// 发送一条消息
        /// </summary>
        /// <param name="SendMsg"></param>
        public void SendOneMsg(ref MessageHeader SendMsg)
        {
            long.TryParse(DateTime.Now.ToString("yyyyMMddHHmmssfff"), out long msgID);
            SendMsg.UserId = (int)UserID.Client_A;
            SendMsg.Timestamp = DateTime.Now;
            SendMsg.MessageID = msgID;
            CommunicationHelper.Instance.WriteOneMsg((int)UserType.Client, SendMsg);
        }

        /// <summary>
        /// 收取一条消息
        /// </summary>
        /// <param name="ReceiveMsg"></param>
        public void ReceiveOneMsg(ref MessageHeader ReceiveMsg)
        {
            CommunicationHelper.Instance.ReadOneMsg((int)UserType.Server, ref ReceiveMsg);
        }
        /// <summary>
        /// 发送一张图片头
        /// </summary>
        /// <param name="iID"></param>
        /// <param name="imageData"></param>
        public void SendOneImageData(int iID, ref ImageData imageData)
        {
            CommunicationHelper.Instance.WriterOneImageData(iID, imageData);
        }
        /// <summary>
        /// 收取一张图片头
        /// </summary>
        /// <param name="iID"></param>
        /// <param name="imageData"></param>
        public void ReceiveOneImageData(int iID, ref ImageData imageData)
        {
            CommunicationHelper.Instance.ReadOneImageData(iID, ref imageData);
        }
        /// <summary>
        /// 收取一张图片buffer+一个条码
        /// </summary>
        /// <param name="iID"></param>
        /// <param name="imageData"></param>
        /// <param name="byteBarcode"></param>
        /// <param name="byteData"></param>
        public void ReceiveOneImageDataBuffer(int iID, ImageData imageData, ref byte[] byteBarcode, ref byte[] byteData)
        {
            CommunicationHelper.Instance.ReadOneImageDataBuffer(iID, imageData, ref byteBarcode, ref byteData);
        }
        /// <summary>
        /// 发送一条心跳信息
        /// </summary>
        /// <param name="SendMsg"></param>
        public void SendOneHeartMsg(ref MessageHeader SendMsg)
        {
            long.TryParse(DateTime.Now.ToString("yyyyMMddHHmmssfff"), out long msgID);
            SendMsg.UserId = (int)UserID.Client_A;
            SendMsg.Timestamp = DateTime.Now;
            SendMsg.MessageID = msgID;
            CommunicationHelper.Instance.WriteOneMsg((int)UserType.ClientHeart, SendMsg);
        }
        /// <summary>
        /// 收取一条心跳信息
        /// </summary>
        /// <param name="ReceiveMsg"></param>
        public void ReceiveOneHeartMsg(ref MessageHeader ReceiveMsg)
        {
            CommunicationHelper.Instance.ReadOneMsg((int)UserType.ServerHeart, ref ReceiveMsg);
        }
        /// <summary>
        /// 回复一条心跳信息
        /// </summary>
        /// <param name="ReceivedMsg"></param>
        /// <param name="SendMsg"></param>
        public void RespondOneHeartMsg(ref MessageHeader ReceivedMsg, ref MessageHeader SendMsg)
        {
            long.TryParse(DateTime.Now.ToString("yyyyMMddHHmmssfff"), out long msgID);
            SendMsg.AnswerMsgID = ReceivedMsg.MessageID;
            SendMsg.UserId = (int)UserID.Client_A;
            SendMsg.Timestamp = DateTime.Now;
            SendMsg.MessageID = msgID;
            CommunicationHelper.Instance.WriteOneMsg((int)UserType.ClientHeart, SendMsg);
        }
    }
}